﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Sirenix.OdinInspector;
using Sirenix.Utilities;
using UnityEditor;
using UnityEngine;
using FileMode = System.IO.FileMode;

public class CreateNewNode : GlobalConfig<CreateNewNode>
{
    [ReadOnly, LabelText("文件生成路径"), NonSerialized, ShowInInspector]
    public static string defaultPath = "Assets/StoryEditor/Nodes/Action/";
    [ReadOnly, LabelText("格式生成路径"), NonSerialized, ShowInInspector]
    public static string formatPath = "Assets/StoryEditor/Nodes/";
    [ReadOnly, LabelText("格式文件名称"), NonSerialized, ShowInInspector]
    public static string formatFileName = "NodeFormat.cs";
    
    [SerializeField, TabGroup("使用")]
    private DynamicNode node;

    // 是否存在节点
    private bool hasNode
    {
        get
        {
            return node != null;
        }
    }

    public DynamicNode DynamicNode { get; set; }

    [LabelText("节点名称"), HideIf("hasNode"), TabGroup("使用"), OnValueChanged("StringCheck")]
    public string NodeName;

    private void StringCheck(string value)
    {
        NodeName = NodeMethodUtil.ClassNameOnly(value);
    }

    /// <summary>
    /// 管理动态节点
    /// </summary>
    [ShowInInspector, LabelText("动态节点集"), TabGroup("查看")]
    private List<DynamicNode> _nodes;
    
    [Button("创建新节点", ButtonSizes.Large), TabGroup("使用")]
    public void NewNode()
    {
        CtrlAllDynamicNode();
        
        if (string.IsNullOrEmpty(NodeName) || _nodes.Find(n => n.Name == NodeName))
        {
            Debug.LogError("节点名称不能为空 || 节点重名，重新定义");
            return;
        }

        if (node == null)
        {
            node = ScriptableObject.CreateInstance<DynamicNode>();
        }
        
        var nodePath = defaultPath + NodeName + ".asset";
        node.Name = NodeName;
        AssetDatabase.CreateAsset(node, nodePath);
        AssetDatabase.Refresh();
        
        CtrlAllDynamicNode();
    }

    [Button("刷新节点", ButtonSizes.Large), TabGroup("使用")]
    public void UpdateNodes()
    {
        if (node != null)
        {
            node = null;
        }

        CtrlAllDynamicNode();
    }

    [Button("删除节点", ButtonSizes.Large), TabGroup("使用")]
    public void ClearNode()
    {
        if (node == null)
            return;
        
        if (EditorUtility.DisplayDialog("提醒", "清理当前节点？", "ok", "no"))
        {
            NodeMethodUtil.Delete(defaultPath, node.Name+".cs");
            
            AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(node));
            AssetDatabase.Refresh();
            // node = ScriptableObject.CreateInstance<DynamicNode>();
        }
    }

    [Button("刷新剧情导出数据集合", ButtonSizes.Large), GUIColor(0.2f, 0.8f, 0.6f)]
    public void UpdateFormat()
    {
        List<NodeProperty> props = new List<NodeProperty>();
        for (int i = 0; i < _nodes.Count; i++)
        {
            var node = _nodes[i];
            foreach (var nodeProperty in node.props)
            {
                if (props.Find(p=>p.PropName == nodeProperty.PropName) == null)
                    props.Add(nodeProperty);   
            }
        }
        
        var filePath = NodeMethodUtil.Delete(formatPath, formatFileName);
        using (var sw = new StreamWriter(File.Open(filePath, FileMode.OpenOrCreate), Encoding.UTF8))
        {
            var scriptTxt = new StringBuilder();
            scriptTxt.Append("using System.Collections.Generic;\n");
            scriptTxt.Append("using System.ComponentModel;\n");
            scriptTxt.Append("using System.Linq;\n");
            scriptTxt.Append("using BearUtil;\n");
            scriptTxt.Append("using BearUtil.Hidden;\n");
            scriptTxt.Append("using UnityEngine;\n");
            scriptTxt.Append("using Node = XNode.Node;\n\n");
            scriptTxt.Append("public class DialogData\n");
            scriptTxt.Append("{\n");
            scriptTxt.Append("\t[Description(\"顺序\")] public int id;\n");
            scriptTxt.Append("\t[Description(\"类型\")] public int type;\n");
            scriptTxt.Append("\t[Description(\"是否属于存档点\")] public int back_step;\n");
            scriptTxt.Append("\t[Description(\"子节点\")] public int[][] child_node;\n");
            
            // talk node 特殊处理
            scriptTxt.Append("\t[Description(\"角色名称\")] public int role_id;\n");
            scriptTxt.Append("\t[Description(\"角色名称\")] public string role_name;\n");
            scriptTxt.Append("\t[Description(\"立绘资源\")] public string[] icon_portrait;\n");
            scriptTxt.Append("\t[Description(\"角色位置\")] public int portrait_direction;\n");
            scriptTxt.Append("\t[Description(\"文本 key\")] public string lines;\n");
            scriptTxt.Append("\t[Description(\"台词显示在场景\")] public bool is_show_scene;\n");
            scriptTxt.Append("\t[Description(\"气泡样式\")] public int lines_bubble;\n");
            scriptTxt.Append("\t[Description(\"文本速度\")] public int lines_speed;\n");
            // scriptTxt.Append("\t[Description(\"音频名称\")] public string voice;\n");
            scriptTxt.Append("\t[Description(\"场景气泡\")] public int scene_bubble;\n");
            scriptTxt.Append("\t[Description(\"文本选择 key\")] public string[] choose_text;\n");
            scriptTxt.Append("\t[Description(\"展示图片\")] public string[] icon_pic;\n");
            
            
            for (int i = 0; i < props.Count; i++)
            {
                var p = props[i];
                
                if (p.PropName.Equals("lines") || 
                    p.PropName.Equals("role_id") || 
                    p.PropName.Equals("id") ||
                    p.PropName.Equals("type") ||
                    p.PropName.Equals("back_step") ||
                    p.PropName.Equals("child_node") ||
                    p.PropName.Equals("role_name") ||
                    p.PropName.Equals("icon_portrait") ||
                    p.PropName.Equals("portrait_direction") ||
                    p.PropName.Equals("is_show_scene") ||
                    p.PropName.Equals("lines_bubble") ||
                    p.PropName.Equals("lines_speed") ||
                    p.PropName.Equals("scene_bubble") ||
                    p.PropName.Equals("choose_text") ||
                    p.PropName.Equals("icon_pic"))
                    continue;

                scriptTxt.Append($"\t[Description(\"{ p.Desc }\")] ");
                switch (p.Type)
                {
                    case NodePropertyType.Boolean:
                        scriptTxt.Append($"public bool {p.PropName};\n");
                        break;
                    case NodePropertyType.Float:
                        scriptTxt.Append($"public float {p.PropName};\n");
                        break;
                    case NodePropertyType.Node:
                    case NodePropertyType.ArrayInt:
                        scriptTxt.Append($"public int[] {p.PropName};\n");
                        break;
                    case NodePropertyType.AudioPlayData:
                    case NodePropertyType.String:
                        scriptTxt.Append($"public string {p.PropName};\n");
                        break;
                    case NodePropertyType.ArrayString:
                        scriptTxt.Append($"public string[] {p.PropName};\n");
                        break;
                    case NodePropertyType.ActorID:
                    case NodePropertyType.Int:
                    case NodePropertyType.Direction:
                        scriptTxt.Append($"public int {p.PropName};\n");
                        break;
                    case NodePropertyType.Vector2:
                        scriptTxt.Append($"public float {p.PropName}_x;\n");
                        scriptTxt.Append($"\t[Description(\"{ p.Desc }_y\")] ");
                        scriptTxt.Append($"public float {p.PropName}_y;\n");
                        break;
                    default:
                        var dp = CreateNewProperty.Instance.GetProperty(p.Type.ToString());
                        if (dp == null)
                        {
                            Debug.LogError("[CreateNewNode]Type lost: " + p.Type.ToString());
                            return;
                        }
                        else
                        {
                            var valueType = dp.PType.ToString().ToLower();
                            scriptTxt.Append($"public {valueType} {p.PropName};\n");
                            break;
                        }
                }
            }
            
            scriptTxt.Append("}\n");
            
            sw.Write(scriptTxt.ToString());
            sw.Close();
        }

        Debug.Log("【CreateNewNode】 Format scripte 生成成功");
    }

    // dynamic node 收集管理
    public void CtrlAllDynamicNode()
    {
        if (_nodes == null)
            _nodes = new List<DynamicNode>();
        
        _nodes.Clear();
        // 检索 default 路径，管理 dynamic nodes
        string folderPath = Application.dataPath.Replace("Assets", defaultPath);

        if (!Directory.Exists(folderPath))
        {
            Debug.LogError("[CreateNewNode]指向路径丢失，请创建指定路径");
            return;
        }

        var files = Directory.GetFiles(folderPath, "**.asset", SearchOption.AllDirectories);
        for (int i = 0; i < files.Length; i++)
        {
            var file = files[i];
            var path = file.Replace(Application.dataPath, "Assets");

            var node = AssetDatabase.LoadAssetAtPath<DynamicNode>(path);
            if (node == null)
                continue;
            
            _nodes.Add(node);
        }
    }
}

/// <summary>
/// 节点属性
/// </summary>
[Serializable]
public class NodeProperty
{
    [LabelText("属性名称"), OnValueChanged("stringOnly")]
    public string PropName;
    
    [LabelText("描述（选填）")]
    public string Desc = "";
    
    public NodePropertyType Type = NodePropertyType.Int;

    public void stringOnly(string v)
    {
        PropName = NodeMethodUtil.StringOnly(v);
    }
}
